package com.lancoo.edu.platform.operation.commons.service.api;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.lancoo.edu.platform.operation.commons.domain.api.system.*;
import com.lancoo.edu.platform.operation.commons.config.LancooConfig;
import com.lancoo.edu.platform.operation.commons.constant.CodeConstant;
import com.lancoo.edu.platform.operation.commons.constant.base.BaseUrlConstant;
import com.lancoo.edu.platform.operation.commons.domain.api.code.*;
import com.lancoo.edu.platform.operation.commons.exception.ServiceException;
import com.lancoo.edu.platform.operation.commons.utils.EncryptUtil;
import com.lancoo.edu.platform.operation.commons.utils.HttpUtil;
import com.lancoo.edu.platform.operation.commons.utils.TimeUtil;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 基础平台【总API】业务逻辑
 * @author pky
 */
@Service
@Slf4j
public class YunBaseApiService {

    /**
     * 基础平台地址
     */
    @Value("${baseAddr}")
    public String baseUrl;

    /**
     * 新基础平台：智慧校园集成版本号
     */
    public static final String NEW_VERSION = "4.0,4.0+";


    /**
     * 设置appId和accessToken参数
     *
     * @return appId 和 token 的 md5 反序
     */
    public String setAppIdAndAccessToken() {
        return "appid=" + LancooConfig.SYS_ID + "&access_token=" + EncryptUtil.md5AndRevert(LancooConfig.SYS_ID);
    }

    /**
     * 获取参数集Map
     *
     * @return 参数集
     */
    protected Map<String, String> getParamMap() {
        return new HashMap<>(16);
    }
    /**
     * 获取参数集Map
     *
     * @return 参数集
     */
    protected Map<String, String> getParamsMap() {
        Map<String, String> paramsMap = new HashMap<>(16);
        paramsMap.put("appid", LancooConfig.SYS_ID);
        paramsMap.put("access_token", EncryptUtil.md5AndRevert(LancooConfig.SYS_ID));
        return paramsMap;
    }

    /**
     * 获取参数集Map
     *
     * @return 参数集
     */
    protected Map<String, String> getParamsMapforCenter() {
        Map<String, String> paramsMap = new HashMap<>(16);
        paramsMap.put("appId", LancooConfig.SYS_ID);
        paramsMap.put("accessToken", EncryptUtil.md5AndRevert(LancooConfig.SYS_ID));
        return paramsMap;
    }

    /**
     * 设置请求头Map
     * @param token 令牌
     * @return 参数集
     */
    protected Map<String, String> getHeader(String token) {
        Map<String, String> headerMap = new HashMap<>(16);
        headerMap.put("Authorization", "X-Token=" + token);
        return headerMap;
    }

    /**
     * 提取请求结果中的数据
     *
     * @param resultStr     返回结果字符串
     * @param typeReference 反序列化类型
     * @return 结果数据
     */
    protected <T> T getData(String resultStr, TypeReference<CodeInfo<T>> typeReference) {
        if (StringUtils.isBlank(resultStr)) {
            return null;
        }
        CodeInfo<T> codeInfo = JSONObject.parseObject(resultStr, typeReference);
        if (codeInfo.getCode() == CodeConstant.CODE) {
            return codeInfo.getData();
        }
        return null;
    }

    /**
     * 提取请求结果中的数据
     *
     * @param resultStr     返回结果字符串
     * @param typeReference 反序列化类型
     * @return 结果数据
     */
    protected <T> T getData2(String resultStr, TypeReference<Code2Info<T>> typeReference) {
        if (StringUtils.isBlank(resultStr)) {
            return null;
        }
        Code2Info<T> code2Info = JSONObject.parseObject(resultStr, typeReference);
        if (code2Info.getCode() == CodeConstant.CODE && code2Info.getStatus() == CodeConstant.STATUS) {
            return code2Info.getData();
        }
        return null;
    }

    /**
     * 提取请求结果中的数据
     *
     * @param resultStr     返回结果字符串
     * @param typeReference 反序列化类型
     * @return 结果数据
     */
    protected <T> T getData3(String resultStr, TypeReference<Code3Info<T>> typeReference) {
        if (StringUtils.isBlank(resultStr)) {
            return null;
        }
        Code3Info<T> code3Info = JSONObject.parseObject(resultStr, typeReference);
        if (code3Info.getCode() == CodeConstant.CODE && code3Info.getStatus() == CodeConstant.STATUS) {
            return code3Info.getData();
        }
        return null;
    }

    /**
     * 提取请求结果中的数据
     *
     * @param resultStr     返回结果字符串
     * @param typeReference 反序列化类型
     * @return 结果数据
     */
    protected <T> T getData5(String resultStr, TypeReference<Code5Info<T>> typeReference) {
        if (StringUtils.isBlank(resultStr)) {
            return null;
        }
        Code5Info<T> code5Info = JSONObject.parseObject(resultStr, typeReference);
        if (code5Info.getCode() == CodeConstant.STATUS) {
            return code5Info.getData();
        }
        return null;
    }

    /**
     * 提取请求结果中的数据
     *
     * @param resultStr     返回结果字符串
     * @param typeReference 反序列化类型
     * @return 结果数据
     */
    protected <T> T getData9(String resultStr, TypeReference<Code9Info<T>> typeReference) {
        try {
            if (StringUtils.isBlank(resultStr)) {
                return null;
            }
            Code9Info<T> code9Info = JSONObject.parseObject(resultStr, typeReference);
            if (code9Info.getStatus() == CodeConstant.STATUS) {
                return code9Info.getData();
            }
        } catch (Exception e) {
            return null;
        }
        return null;
    }


    /**
     * 提取请求结果中的数据
     *
     * @param resultStr     返回结果字符串
     * @param typeReference 反序列化类型
     * @return 结果数据
     */
    protected <T> List<T> getDataList(String resultStr, TypeReference<Code2Info<List<T>>> typeReference) {
        if (StringUtils.isBlank(resultStr)) {
            return Collections.emptyList();
        }
        try{
            Code2Info<List<T>> code2Info = JSONObject.parseObject(resultStr, typeReference);
            if (code2Info.getCode() == CodeConstant.CODE && code2Info.getStatus() == CodeConstant.STATUS) {
                return code2Info.getData();
            }
        } catch (Exception e){
            return Collections.emptyList();
        }
        return Collections.emptyList();
    }

    /**
     * 提取请求结果中的数据
     *
     * @param resultStr     返回结果字符串
     * @param typeReference 反序列化类型
     * @return 结果数据
     */
    protected <T> List<T> getDataListV2(String resultStr, TypeReference<CodeBasePlatform<List<T>>> typeReference) {
        if (StringUtils.isBlank(resultStr)) {
            return Collections.emptyList();
        }
        try {
            CodeBasePlatform<List<T>> codeBasePlatform = JSONObject.parseObject(resultStr, typeReference);
            if (codeBasePlatform.getCode() == CodeConstant.CODE && codeBasePlatform.getStatus() == CodeConstant.STATUS) {
                return codeBasePlatform.getData();
            }
        } catch (Exception e) {
            return Collections.emptyList();
        }
        return Collections.emptyList();
    }


    /**
     * 提取请求结果中的数据
     *
     * @param resultStr     返回结果字符串
     * @param typeReference 反序列化类型
     * @return 结果数据
     */
    protected <T> List<T> getData3List(String resultStr, TypeReference<Code3Info<List<T>>> typeReference) {
        if (StringUtils.isBlank(resultStr)) {
            return Collections.emptyList();
        }
        Code3Info<List<T>> code3Info = JSONObject.parseObject(resultStr, typeReference);
        if (code3Info.getCode() == CodeConstant.CODE && code3Info.getStatus() == CodeConstant.STATUS) {
            return code3Info.getData();
        }
        return null;
    }

    /**
     * 获取产品初始化配置信息
     * @return 产品初始化配置信息
     */
    public ProductInfo getProductInfo() {
        String url = baseUrl + "/BaseApi/Global/GetBaseProductsInfo";
        Map<String, String> paramsMap = getParamsMap();
        String resultStr = HttpUtil.sendGet(url, paramsMap);
        // 设置json 反序列化类型，并提取data数据返回
        return getData2(resultStr, new TypeReference<Code2Info<ProductInfo>>(){});
    }

    /**
     * 获取教育局Id
     * @return 教育局ID
     */
    public String getEduId() {
        String url = baseUrl + "/BaseApi/Global/GetBaseProductsInfo";
        Map<String, String> paramsMap = getParamsMap();
        String sendPost = HttpUtil.sendGet(url, paramsMap);
        // 设置json 反序列化类型，并提取data数据返回
        JSONObject resultJson = JSONObject.parseObject(sendPost);
        JSONObject data = resultJson.getJSONObject(CodeConstant.DATE_STR_BIG);
        return data.getString("EduID");
    }

    /**
     * 获取基础平台下指定子系统的服务器配置信息
     * （此方法只支持获取一个子系统的信息，不支持获取多个）
     *
     * @param sysId 指定子系统ID
     * @return 子系统信息
     */
    public ServerInfo getOneServerInfo(String sysId) {
        String url = baseUrl + BaseUrlConstant.SERVER_INFO_URL + "?" + setAppIdAndAccessToken() + "&sysIDs=" + sysId;
        String resultStr = HttpUtil.sendGet(url);
        if (StringUtils.isNotBlank(resultStr)) {
            Code2Info<List<ServerInfo>> code2Info = JSONObject.parseObject(resultStr,
                    new TypeReference<Code2Info<List<ServerInfo>>>() {
                    });
            if (code2Info.getCode() == CodeConstant.CODE && code2Info.getStatus() == CodeConstant.STATUS) {
                return code2Info
                        .getData()
                        .stream()
                        .filter(serverInfo -> serverInfo
                                .getSysId()
                                .equalsIgnoreCase(sysId))
                        .findFirst()
                        .orElse(null);
            }
        }
        return null;
    }

    /**
     * 获取基础平台下指定子系统的服务器配置信息
     * @param sysIds 指定子系统ID串，用英文逗号隔开
     * @return 子系统列表
     */
    public List<ServerInfo> getServerInfoList(String sysIds) {
        String url = baseUrl + BaseUrlConstant.SERVER_INFO_URL + "?" + setAppIdAndAccessToken() + "&sysIDs=" + sysIds;
        String resultStr = HttpUtil.sendGet(url);
        return getDataList(resultStr, new TypeReference<Code2Info<List<ServerInfo>>>() {});
    }


    /**
     * 获取子系统的访问状态
     * @param sysIds 子系统id串，使用逗号进行分隔，不可为空
     * @return 子系统的访问状态列表
     */
    public List<SystemStatusApi> getSysState(String sysIds){
        String url = baseUrl + BaseUrlConstant.SYSTEM_STATE + "?" + setAppIdAndAccessToken() + "&sysIDs=" + sysIds;
        String resultStr = HttpUtil.sendGet(url);
        List<SystemStatusApi> dataList = getDataList(resultStr, new TypeReference<Code2Info<List<SystemStatusApi>>>() {
        });
        dataList = dataList.stream().filter(stateInfo -> !StringUtils.contains(stateInfo.getSysId(),"<")).collect(Collectors.toList());
        return dataList;
    }

    /**
     * 请求基础平台返回状态码是否为 200
     * @param resultStr 请求结果
     * @return true：成功，false：失败
     */
    protected <T> boolean requestBaseStatus(String resultStr){
        String errorMsg = null;
        if (StringUtils.isBlank(resultStr)) {
            return false;
        }
        try {
            JSONObject resultJson = JSONObject.parseObject(resultStr);
            if (!Objects.equals(resultJson.getInteger(CodeConstant.STATUS_CODE_STR), CodeConstant.STATUS)) {
                errorMsg = (resultJson.getString(CodeConstant.MSG_STR_BIG));
            }
        } catch (Exception e) {
            return false;
        }
        if (StringUtils.isNotBlank(errorMsg)) {
            throw new ServiceException(errorMsg);
        }
        return true;
    }

    /**
     * 获取基础平台下指定子系统的内网服务器配置信息
     * （此方法只支持获取一个子系统的信息，不支持获取多个）
     *
     * @param sysId 指定子系统ID
     * @return 子系统信息
     */
    public ServerInfo getOneInnerServerInfo(String sysId) {
        String url = baseUrl + BaseUrlConstant.SERVER_INFO_INNER_URL + "?" + setAppIdAndAccessToken() + "&sysIDs=" + sysId;
        return getServerInfo(sysId, url);
    }

    /**
     * 获取系统的根地址
     *
     * @return 地址
     */
    protected String getSysWebUrl(String sysId, String sysName) {
        ServerInfo serverInfo = getOneServerInfo(sysId);
        if (Objects.isNull(serverInfo)) {
            log.error("基础平台未配置" + sysName + "信息");
            return baseUrl;
        }
        return serverInfo.getWebSvrAddr();
    }

    /**
     * 获取子系统服务器地址
     *
     * @param sysId 子系统系统ID
     * @param url   获取子系统服务器地址（分内网和外网）
     * @return 子系统服务器地址
     */
    public ServerInfo getServerInfo(String sysId, String url) {
        String resultStr = HttpUtil.sendGet(url);
        if (StringUtils.isNotBlank(resultStr)) {
            Code2Info<List<ServerInfo>> code2Info = JSONObject.parseObject(resultStr,
                    new TypeReference<Code2Info<List<ServerInfo>>>() {
                    });
            if (code2Info.getCode() == CodeConstant.CODE && code2Info.getStatus() == CodeConstant.STATUS) {
                return code2Info
                        .getData()
                        .stream()
                        .filter(serverInfo -> serverInfo
                                .getSysId()
                                .equalsIgnoreCase(sysId))
                        .findFirst()
                        .orElse(null);
            }
        }
        return null;
    }

    /**
     * 判断是否是java版基础平台
     * @return true是，false不是
     */
    public Boolean beJavaBasePlatform(){
        ProductInfo productInfo = getProductInfo();
        return Objects.nonNull(productInfo) && StringUtils.contains(NEW_VERSION,productInfo.getIsVersion());
    }

    /**
     * 获取锁控信息
     * @param eduId 教育局ID
     * @param lockerId 锁控
     * @return 锁控信息
     */
    public LockerInfo getLockInfo(String eduId, String lockerId) {
        String url = baseUrl + "/BaseApi/LockerMgr/GetSubSystemLockerInfoByID";
        Map<String, String> paramsMap = getParamsMap();
        paramsMap.put("eduID", StringUtils.isBlank(eduId) ? "" : eduId);
        paramsMap.put("lockerID", lockerId);
        String timeStr = TimeUtil.getCurrentTimeBySecond();
        paramsMap.put("requestTime", timeStr);
        String secCode = EncryptUtil.md5AndRevert(lockerId + timeStr);
        paramsMap.put("secCode", secCode);
        // 检测锁控
        String resultStr = HttpUtil.sendGet(url, paramsMap);
        // 设置json 反序列化类型，并提取data数据返回
        LockerInfo lockerInfo = getData2(resultStr, new TypeReference<Code2Info<LockerInfo>>() {
        });
        if (lockerInfo != null) {
            lockerInfo.setLockErrAddr(baseUrl + "LockerMgr/ErrorTips.aspx?ErrorCode=");
        }
        return lockerInfo;
    }

    /**
     * 检查锁控信息
     *
     * @return 锁控信息检查结果
     */
    public LockerInfo checkLocker(String sysId, String lockerId) {
        // 设置参数
        String timeStr = TimeUtil.getCurrentTimeBySecond();
        String secCode = EncryptUtil.md5AndRevert(lockerId + timeStr);
        String params = lockerId + "|" + timeStr;
        String url = baseUrl + BaseUrlConstant.CHECK_LOCKER_URL + "?method=GetSubSystemLockerInfoByID&params=" + params + "&SecCode=" + secCode;
        // 检测锁控
        String resultStr = HttpUtil.sendGet(url);
        // 设置json 反序列化类型，并提取data数据返回
        LockerInfo lockerInfo = getData(resultStr, new TypeReference<CodeInfo<LockerInfo>>() {
        });
        if (lockerInfo != null) {
            lockerInfo.setLockErrAddr(baseUrl + "LockerMgr/ErrorTips.aspx?ErrorCode=");
        }
        return lockerInfo;
    }

    /**
     * 获取子系统的服务器内网地址
     *
     * @param sysIds   系统ID串
     * @param eduId 教育局ID
     * @return 服务器信息列表
     */
    public List<ServerInfo> getInnerServerInfoList(String sysIds, String eduId) {
        String url = baseUrl + BaseUrlConstant.SERVER_INFO_INNER_URL;
        Map<String, String> paramsMap = getParamsMap();
        paramsMap.put("sysIDs", sysIds);
        // paramsMap.put("schoolId", schoolId);
        String resultStr = HttpUtil.sendGet(url, paramsMap);
        //设置json反序列化类型,并提取data数据返回
        return getDataListV2(resultStr, new TypeReference<CodeBasePlatform<List<ServerInfo>>>() {
        });
    }

    /**
     * 获取子系统的服务器数据库Ip地址列表
     *
     * @param sysIds   系统ID串
     * @param eduId 教育局ID
     * @return 服务器信息列表
     */
    public List<ServerDatabaseIpInfo> getDatabaseIpInfoList(String sysIds, String eduId) {
        String url = baseUrl + BaseUrlConstant.GET_DATABASE_IP_BY_SYS_ID_URL;
        Map<String, String> paramsMap = getParamsMap();
        paramsMap.put("sysIds", sysIds);
        paramsMap.put("schoolId", eduId);
        String resultStr = HttpUtil.sendGet(url, paramsMap);
        //设置json反序列化类型,并提取data数据返回
        return getDataListV2(resultStr, new TypeReference<CodeBasePlatform<List<ServerDatabaseIpInfo>>>() {
        });
    }
}
